--[[
This file holds the function related to loading files and calling lua chuncks
in the simulated environment.

the following simulated functions are defined here :

	seterrorhandler()
	geterrorhandler()
]]

local xpcall = xpcall
local DEBUG = config.DEBUG
local env = api.global._G

local default_errorhandler = function (msg)
	log("EE default handler for error : %s", debug.traceback(msg))
	if DEBUG then
		print(debug.traceback(msg))
		coroutine.yield("debug")
	end
end

local env_error_callback = function (msg)
	log("EE error in CALLBACK : %s", debug.traceback(msg))
	if DEBUG then
		print(debug.traceback(msg))
		coroutine.yield("debug")
	end
end

function api.global.seterrorhandler(handler)
	api.errorhandler = function (...)
		print(debug.traceback(...))
		return handler(...)
	end
end

function api.global.geterrorhandler()
	return api.errorhandler or default_errorhandler
end

local function cocall(func, error_handler)
	if DEBUG then
		local result, err
		local co = coroutine.create(function () xpcall(func, error_handler) end)
		while coroutine.status(co) ~= "dead" do
			result, err = coroutine.resume(co)
			if not result then
				log("EE Error in coroutine : %s\n", tostring(err))
				return
			elseif err == "debug" then
				BUG_CO = co
				debug.debug()
				BUG_CO = nil
			end
		end
		return result, err
	else
		return xpcall(func, error_handler)
	end
end

local env_error = function (msg)
	local handler = api.errorhandler and function()
		print("ERROR", debug.traceback(msg, 4))
		debug.debug()
		log("EE error in CALLBACK : %s", debug.traceback(msg, 4))
		api.errorhandler(msg)
	end or function ()
		default_errorhandler(msg)
	end
	cocall(handler, env_error_callback)
	return debug.traceback(msg)
end

local call = function(func)
	if type(func) == "string" then
		local f, err = loadstring(func)
		if not f then return nil, err end
		func = f
	end
	setfenv(func, env)
	return cocall(func, env_error)
end

local dofile
local function setxmlinput(opt)
	local G = api.global
	if opt then
		G.RegisterFrame = UI.RegisterFrame
		G.RegisterFont = UI.RegisterFont
		G.SetFrameProtected = UI.SetFrameProtected
		G.DeclareBinding = bindings.Declare
		G.dofile = dofile
	else
		G.RegisterFrame = nil
		G.RegisterFont = nil
		G.SetFrameProtected = nil
		G.DeclareBinding = nil
		G.dofile = nil
	end
end

local function loadlua(src, name, security, nocache)
	Security:set(name, security)
	local func, err = cache.loadfile(src, nocache)
	if not func then
		log("EE Error loading file : %s", tostring(err))
		return nil, err
	else
		log("++ Loading file %s", src)
	end
	local result, err = call(func)
	if not result then
		log("EE executing file : %s", tostring(err))
	end
end

local function loadxml(src, name, security, nocache)
	Security:set(name, security)
	local func, err = cache.loadxml(src, nocache)
	if not func then
		log("EE Error loading file : %s", tostring(err))
		return nil, err
	else
		log("++ Loading file %s", src)
	end
	setxmlinput(true)
	local result, err = call(func)
	setxmlinput(false)
	if not result then
		log("EE executing file : %s", tostring(err))
	end
end

api.call = call
api.loadlua = loadlua
api.loadxml = loadxml

function dofile(filename)
	loadlua(filename, Security.taint, Security.level)
end
